home *** CD-ROM | disk | FTP | other *** search
/ Aminet 38 / Aminet 38 (2000)(Schatztruhe)[!][Aug 2000].iso / Aminet / dev / src / xad_bzip2.lha / bzip2.c next >
Encoding:
C/C++ Source or Header  |  2000-05-19  |  9.3 KB  |  305 lines

  1. /* This XAD client is written by Kyzer/CSG <kyzer@4u.net>, the actual
  2.  * decompression code is written by bzip2's author, Julian Seward. bzip2
  3.  * is (C) 1996-2000 Julian R. Seward. Please see some of his files for more
  4.  * information.
  5.  *
  6.  * License:
  7.  * - The modified and unmodified files of libbzip2 are (C) Julian R. Seward
  8.  *   and retain their original license. However, you should not directly
  9.  *   use these modified versions, you should obtain the original bzip2
  10.  *   and libbzip2 from http://sourceware.cygnus.com/bzip2/
  11.  * - This slave and its source code is licensed to Dirk Stoecker for
  12.  *   inclusion in his XAD distribution without further conditions.
  13.  * - For all other people, this slave is licensed under the GNU General
  14.  *   public license, version 2.
  15.  *
  16.  * Although this slave should work perfectly with an unmodifed libbzip2
  17.  * compiled with BZ_NO_STDIO, I have made changes:
  18.  * - all compression-related code is removed. It is unneccessary in a
  19.  *   decompression-only slave.
  20.  * - all high level functionality in bzlib.c is removed, leaving only
  21.  *   low-level decompression code - bzDecompress(Init|%|End)
  22.  * - the decompresser has been modified to try and enter 'small mode' if
  23.  *   it cannot allocate enough memory for 'fast mode'.
  24.  * - 'assertion failures' are turned into error codes, as this slave can't
  25.  *   support the immediate exit() that libbzip2 would like.
  26.  * - the random number table rNums has been made into Int16 instead of Int32
  27.  */
  28.  
  29. /* bzip2 is actually just a file compressor, and doesn't even include any
  30.  * details about the file itself - perhaps this should be an XFD slave
  31.  * instead? A couple of reasons why not:
  32.  *
  33.  * 1. tar files are archives. gzip'ed tar files are archives too. 99% of
  34.  *    bzip2 compressed files are tar archives. therefore, if gzip is an xad
  35.  *    slave, bzip2 is an xad slave too.
  36.  *
  37.  * 2. bzip2 takes astonishing amounts of memory to unpack - it's far more a
  38.  *    UNIX archive compressor than it is a realtime depacker for demos and
  39.  *    games, which is the ethos of XFD compressors.
  40.  */
  41.  
  42. /* bzip2 file format:
  43.  * - first, the header: 'BZh1' to 'BZh9'
  44.  *   - the 1-9 in the header is the size of a block / 100000
  45.  *
  46.  * - next, 0 or more compressed data blocks
  47.  *   - the block starts with recogdata: $314159265359 (BCD pi :)
  48.  *   - then comes a 4 byte CRC-so-far
  49.  *   - then the various state tables
  50.  *   - then the sorted randomized huffed RLE data
  51.  *
  52.  * - a final block containing no data is always included
  53.  *   - it's recog is $177245385090, however after the first block
  54.  *     the data is 87.5% likely not to be byte aligned, so you probably
  55.  *     won't see it in a hex editor.
  56.  *   - there's a 4 byte final CRC, but for the reason mentioned above,
  57.  *     it's difficult to check.
  58.  *
  59.  * - minimum size of file is 14 bytes for a 0 byte input file (just a
  60.  *   header and the final block, no data blocks), or 37 bytes for a 1 byte
  61.  *   input file
  62.  *
  63.  * bzip2, by virtue of early recklessness and backwards compatibility on
  64.  * the part of the author, does not contain *any* information whatsoever
  65.  * about the data itself, it can't even know how long a block is without
  66.  * decompressing it. But hey! It beats gzip on compression, so that's got
  67.  * to be good, right?
  68.  */
  69.  
  70. /* $VER: bzip2.c 1.2 (19.05.00) */
  71.  
  72. #include <exec/memory.h>
  73. #include <string.h>
  74.  
  75. #include <libraries/xadmaster.h>
  76. #include <proto/xadmaster.h>
  77.  
  78. #include "bzlib.h"
  79.  
  80. #include "SDI_compiler.h"
  81. #define XADBASE  REG(a6, struct xadMasterBase *xadMasterBase)
  82.  
  83. #ifdef DEBUG
  84. void KPrintF(char *fmt, ...);
  85. #define D(x) x
  86. #define BG KPrintF
  87. #else
  88. #define D(x)
  89. #define BG
  90. #endif
  91.  
  92.  
  93. #ifndef XADMASTERFILE
  94. #define bzip2_Client        FirstClient
  95. #define NEXTCLIENT        0
  96. const UBYTE version[] = "$VER: bzip2 1.2 (19.05.00)";
  97. #endif
  98. #define BZIP2_VERSION        1
  99. #define BZIP2_REVISION        0
  100.  
  101.  
  102. /*--- memory functions -----------------------------------------------------*/
  103.  
  104. struct xadMasterBase *xadBase;
  105.  
  106. struct mh {
  107.   struct mh *next;
  108. };
  109.  
  110. struct mh *initmem(XADBASE) {
  111.   struct mh *base = (struct mh *) xadAllocVec(sizeof(struct mh), 0);
  112.   xadBase = xadMasterBase;
  113.   if (base) base->next = NULL;
  114.   return base;
  115. }
  116.  
  117. APTR allocmem(struct mh *base, ULONG size, ULONG flags) {
  118.   struct xadMasterBase *xadMasterBase = xadBase;
  119.   struct mh *mem = (struct mh *) xadAllocVec(size + sizeof(struct mh), flags);
  120.   if (!mem) return NULL;
  121.   mem->next = base->next; /* link into list */
  122.   base->next = mem;
  123.   return (APTR) ++mem;
  124. }
  125.  
  126. void freemem(struct mh *base, APTR mem) {
  127.   struct xadMasterBase *xadMasterBase = xadBase;
  128.   struct mh *m, *x, *o;
  129.  
  130.   if (!mem || !base) return;
  131.   m = (struct mh *) mem;  m--; /* get correct address */
  132.  
  133.   for (o = base; (x = o->next); o = x) {
  134.     if (x == m) {
  135.       o->next = x->next;
  136.       xadFreeObjectA((APTR)x, NULL);
  137.       return;
  138.     }
  139.   }
  140. }
  141.  
  142. void freeallmem(struct mh *base) {
  143.   struct xadMasterBase *xadMasterBase = xadBase;
  144.   while (base) {
  145.     struct mh *next = base->next;
  146.     xadFreeObjectA((APTR)base, NULL);
  147.     base = next;
  148.   }
  149. }
  150.  
  151.  
  152. /*--- xad slave -------------------------------------------------------------*/
  153.  
  154. ASM(BOOL) bzip2_RecogData(REG(d0, ULONG size), REG(a0, STRPTR data), XADBASE) {
  155.  
  156.   /* check file header */
  157.   if (data[0] != 'B' || data[1] != 'Z' || data[2] != 'h') return 0;
  158.   if (data[3] <  '1' || data[3] > '9') return 0;
  159.  
  160.   /* check first block header */
  161.  
  162.   if (data[4] == 0x31) {
  163.     if (data[5] != 0x41 || data[6] != 0x59) return 0;
  164.     if (data[7] != 0x26 || data[8] != 0x53 || data[9] != 0x59) return 0;
  165.   }
  166.   else {
  167.     if (data[4] != 0x17 || data[5] != 0x72 || data[6] != 0x45) return 0;
  168.     if (data[7] != 0x38 || data[8] != 0x50 || data[9] != 0x90) return 0;
  169.   }  
  170.  
  171.   /* we're happy with it */
  172.   return 1;
  173. }
  174.  
  175.  
  176. ASM(LONG) bzip2_GetInfo(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
  177.   struct TagItem datetags[] = {
  178.     { XAD_DATECURRENTTIME, 1 },
  179.     { XAD_GETDATEXADDATE,  0 },
  180.     { TAG_DONE, 0 }
  181.   };
  182.  
  183.   /* there's only one file in a bzip archive - the uncompressed data */
  184.   struct xadFileInfo *fi;
  185.  
  186.   fi = (struct xadFileInfo *) xadAllocObjectA(XADOBJ_FILEINFO, NULL);
  187.   if (!(ai->xai_FileInfo = fi)) return XADERR_NOMEMORY;
  188.  
  189.   fi->xfi_Flags       = XADFIF_NODATE     | XADFIF_NOUNCRUNCHSIZE 
  190.                       | XADFIF_NOFILENAME | XADFIF_SEEKDATAPOS;
  191.   fi->xfi_EntryNumber = 1;
  192.   fi->xfi_FileName    = xadMasterBase->xmb_DefaultName;
  193.   fi->xfi_CrunchSize  = ai->xai_InSize - 14;
  194.   fi->xfi_Size        = 0;
  195.   fi->xfi_DataPos     = 0;
  196.  
  197.   /* fill in today's date */
  198.   datetags[1].ti_Data = (ULONG) &fi->xfi_Date;
  199.   xadConvertDatesA(datetags);
  200.  
  201.   return XADERR_OK;
  202. }
  203.  
  204.  
  205. /* bz2lib support functions */
  206. void bz_internal_error() { }
  207. void *bzalloc(void *base, int a, int b) {
  208.   return allocmem((struct mh *)base, a*b, 0);
  209. }
  210. void bzfree(void *base, void *mem) {
  211.   freemem((struct mh *)base, mem);
  212. }
  213.  
  214.  
  215. ASM(LONG) bzip2_UnArchive(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
  216.   struct mh *base;
  217.   char *buf_in, *buf_out;
  218.   const int bufsize = 8192;
  219.   int size;
  220.   bz_stream bzs;
  221.   LONG err, bzerr;
  222.  
  223.   /* ensure we're decrunching our only file! */
  224.   if (!ai || !ai->xai_CurFile || ai->xai_CurFile->xfi_EntryNumber != 1)
  225.     return XADERR_BADPARAMS;
  226.  
  227.   /* initialise memory system */
  228.   ai->xai_PrivateClient = (APTR) (base = initmem(xadMasterBase));
  229.   bzs.opaque    = base;
  230.   bzs.bzalloc   = bzalloc;
  231.   bzs.bzfree    = bzfree;
  232.  
  233.   /* allocate some buffers */
  234.   buf_in  = allocmem(base, bufsize, MEMF_PUBLIC);
  235.   buf_out = allocmem(base, bufsize, MEMF_PUBLIC);
  236.   if (!buf_in || !buf_out) return XADERR_NOMEMORY;
  237.  
  238.  /* force immediate read-in of data on first run only */
  239.   bzs.avail_in = 0;
  240.  
  241.   /* always keep going - exit is only when demand passes EOF */
  242.   while (1) {
  243.     /* initialise the decompression state */
  244.     if ((bzerr=BZ2_bzDecompressInit(&bzs, 0, 0)) != BZ_OK)
  245.       return XADERR_NOMEMORY;
  246.  
  247.     /* reset output buffer */
  248.     bzs.avail_out = bufsize;
  249.     bzs.next_out  = buf_out;
  250.  
  251.     while (bzerr == BZ_OK) {
  252.       /* fill input buffer when empty */
  253.       if (bzs.avail_in == 0) {
  254.         size = ai->xai_InSize - ai->xai_InPos;
  255.         if (size > bufsize) size = bufsize;
  256.         if (size == 0) return XADERR_OK; /** normal exit point = EOF **/
  257.         if((err = xadHookAccess(XADAC_READ, size, buf_in, ai))) return err;
  258.         bzs.next_in  = buf_in;
  259.         bzs.avail_in = size;
  260.       }
  261.  
  262.       /* do some more decompression */
  263.       bzerr = BZ2_bzDecompress(&bzs);
  264.  
  265.       /* purge any output */
  266.       if ((size = bufsize - bzs.avail_out) > 0) {
  267.         if((err = xadHookAccess(XADAC_WRITE, size, buf_out, ai))) return err;
  268.         bzs.next_out  = buf_out;
  269.         bzs.avail_out = bufsize;
  270.       }
  271.     }
  272.  
  273.     switch (bzerr) {
  274.     case BZ_STREAM_END:       BZ2_bzDecompressEnd(&bzs); break;
  275.     case BZ_DATA_ERROR:
  276.     case BZ_DATA_ERROR_MAGIC: return XADERR_ILLEGALDATA;
  277.     case BZ_MEM_ERROR:        return XADERR_NOMEMORY;
  278.     default:                  return XADERR_DECRUNCH;
  279.     }
  280.   }
  281.   return XADERR_DECRUNCH; /* not reached! */
  282. }
  283.  
  284.  
  285. ASM(void) bzip2_Free(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
  286.   freeallmem((struct mh *) ai->xai_PrivateClient);
  287.   ai->xai_PrivateClient = NULL;
  288. }
  289.  
  290.  
  291. const struct xadClient bzip2_Client = {
  292.   NEXTCLIENT, XADCLIENT_VERSION, 6, BZIP2_VERSION, BZIP2_REVISION,
  293.  
  294.   14,                        /* minimum archive size     */
  295.   XADCF_FILEARCHIVER | XADCF_FREEFILEINFO,    /* type of client and flags */
  296.   0,                        /* internal ID (not needed) */
  297.   "BZip2",                    /* name of client           */
  298.  
  299.   /* client functions */
  300.   (BOOL (*)()) bzip2_RecogData,
  301.   (LONG (*)()) bzip2_GetInfo,
  302.   (LONG (*)()) bzip2_UnArchive,
  303.   (void (*)()) bzip2_Free
  304. };
  305.